10. K8S之svc

10. K8S之svc

回顾一下之前的内容,就会发现,之前创建好的Pod,没有提供一个合理的访问方式

dm

如上图:

如果外部环境想要访问Pod的提供的服务,就算Pod提供了访问,那么也只能一个个的访问:

svc1

而且还会有另外一种情况:

当某一个Pod死掉之后,就算Deployment将Pod的数量恢复到了副本的期望数值,Client也访问不了新的Pod的了。

svc2

此时,就需要介绍K8S另外一个控制器:service(svc)

介绍

Service(简称svc) 提供了一个统一的服务访问入口以及服务代理和发现机制,用户不需要了解后台Pod是如何运行。Service通过Label找到Pod组。
Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。

在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。 kube-proxy 负责为 Service 实现了一种 VIP(虚拟 IP)的形式,而不是 ExternalName 的形式。

例如通过定义一个RS启动了4个pod,如何让外部能优雅的调用到这几个pod提供的服务?由于pod的IP地址可能随时发生变化(pod不健康或期间被重启或被重建等),在pod的外层使用nginx等进行负载也就不太方便了,而Service 就是解决这个问题而存在的:

可以根据pod的标签将对应的所有pod纳入一个负载均衡组的形式,通过kube-proxy 进行数据转发,提供一个外部到pod的唯一入口而不用关心pod的变动,进而实现和外部的调用通信

svc3

代理模式

userspace 代理模式(基本不用了)

这种模式,kube-proxy 会监视 Kubernetes 控制平面对 Service 对象和 Endpoints 对象的添加和移除操作。 对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。 任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods 中的某个上面(如 Endpoints 所报告的一样)。 使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP) 和 Port 的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。

默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。

iptables 代理模式(开销较大)

这种模式,kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。 对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。 对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。

默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。

使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。 这种方法也可能更可靠。

如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。 这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。

你可以使用 Pod 就绪探测器 验证后端 Pod 可以正常工作,以便 iptables 模式下的 kube-proxy 仅看到测试正常的后端。 这样做意味着你避免将流量通过 kube-proxy 发送到已知已失败的 Pod。

IPVS模式(目前最合理)

在 ipvs 模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。 该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。

IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。 这意味着,与 iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。 与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。

IPVS 提供了更多选项来平衡后端 Pod 的流量。

要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。

当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。

所有节点安装:

1
yum install -y ipvsadm

master端修改为ipvs模式

1
2
kubectl edit cm kube-proxy -n kube-system
# 改一下内容:mode: "ipvs"

master端更新kube-proxy

1
kubectl get pod -n kube-system |grep kube-proxy | awk '{system("kubectl delete pod "$1" -n kube-system")}'

无头服务

Headless Service不需要分配一个IP, 而是直接以DNS记录的方式解析出被代理Pod的IP地址。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 "None" 来创建 Headless Service

对这无头 Service 并不会分配 Cluster IP,kube-proxy 不会处理它们, 而且平台也不会为它们进行负载均衡和路由。 DNS 如何实现自动配置,依赖于 Service 是否定义了选择算符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# demo.yml 
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
clusterIP: None
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo2
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v2

域名格式:

1
$(servicename).$(namespace).svc.cluster.local

发布服务

svc有以下4种类型:

1. ClusterIP(默认)

通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType。

2. NodePort(没有ingress情况下的,常见的暴露服务的方式)

通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# demo.yml 
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
ports:
- protocol: TCP
port: 80
targetPort: 80
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo2
spec:
replicas: 4
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:v2

3. LoadBalancer(公有云的暴露方式)

LoadBalancer类型的service 是可以实现集群外部访问服务的另外一种解决方案。不过并不是所有的k8s集群都会支持,大多是在公有云托管集群中会支持该类型。负载均衡器是异步创建的,关于被提供的负载均衡器的信息将会通过Servicestatus.loadBalancer字段被发布出去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# demo.yml
apiVersion: v1
kind: Service
metadata:
name: service-python
spec:
ports:
- port: 3000
protocol: TCP
targetPort: 443
nodePort: 30080
selector:
run: pod-python
type: LoadBalancer

如图:

svc4

访问方式:

1
2
kuebctl get svc
# 通过external-ip 字段的ip地址,来访问服务

4. ExternalName

类型为 ExternalName 的service将服务映射到 DNS 名称,而不是典型的选择器,例如my-service或者cassandra。 您可以使用spec.externalName参数指定这些服务。

创建 ExternalName 类型的服务的 yaml 如下:

1
2
3
4
5
6
7
8
9
# demoExternalName.yml
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com

5. 引入外部IP(externalIPs)

如果外部的 IP 路由到集群中一个或多个 Node 上,Kubernetes Service 会被暴露给这些 externalIPs。 通过外部 IP(作为目的 IP 地址)进入到集群,打到 Service 的端口上的流量, 将会被路由到 Service 的 Endpoint 上。 externalIPs 不会被 Kubernetes 管理,它属于集群管理员的职责范畴。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# demoExternalIPs.yml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
文章作者: 海龟先生
文章链接: http://haiguixiansheng.org.cn/2020/05/20/10. K8S之svc/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 海龟先生
打赏
  • 微信
  • 支付宝

评论